package http

import (
	"context"
	"daxin.my/test-netserver/instrumentation"
	"fmt"
	"go.opentelemetry.io/otel/metric"
	"log"
	net "net/http"
	"net/url"
	"strconv"
	"sync"
	"time"

	"daxin.my/test-netserver/api"
	"daxin.my/test-netserver/middleware"
	"daxin.my/test-netserver/quartz"
)

var mutex sync.Mutex

var counter metric.Int64Counter
var histogram metric.Int64Histogram

type HttpServer struct {
	httpClient api.ProtocolClient
}

func init() {
	counter = metric.Must(instrumentation.Meter).NewInt64Counter("http_requests_total")
	histogram = metric.Must(instrumentation.Meter).NewInt64Histogram("http_request_duration_microseconds")
}

func StartHttpServer(port string, httpClient api.ProtocolClient) {
	if port == "" {
		port = "9000"
	}
	server := HttpServer{
		httpClient: httpClient,
	}
	log.Printf("Start Http Server, port: %s\n", port)
	net.HandleFunc("/test", server.TestHandler)
	net.HandleFunc("/test/", server.TestHandler)
	err := net.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func (server HttpServer) TestHandler(rw net.ResponseWriter, r *net.Request) {
	start := time.Now()

	counter.Add(context.Background(), 1)

	log.Printf("Received HTTP from: %s\n", r.RemoteAddr)
	err := r.ParseForm()
	if err != nil {
		log.Println(err)
		return
	}
	fields := r.Form
	log.Printf("Received HTTP Params: %v\n", r.Form)

	// 请求中间件
	requestMiddlewares(fields)

	// HTTP转发
	httpCallDemo2(
		server.httpClient,
		fields.Get("invoke"),
		fields.Get("bsleep"),
		fields.Get("breqbyte"),
		fields.Get("brespbyte"),
	)

	// 开启关闭定时器
	startOrStopQuartz(fields.Get("quartz"))

	// 设置返回状态码
	setStatusCode(fields.Get("statusCode"), rw)
	// 等待时间
	sleep(fields.Get("sleep"))
	// 设置返回长度
	setResponseBytes(fields.Get("respbyte"), rw)
	// 返回内容
	_, _ = fmt.Fprintf(rw, "Hello world!\n")

	end := time.Now()

	histogram.Record(context.Background(), end.Sub(start).Microseconds())
}

func setStatusCode(statusCode string, rw net.ResponseWriter) {
	code, ok := stringToInt(statusCode)
	if ok && code > 0 {
		rw.WriteHeader(code)
	}
}

func sleep(duration string) {
	sleepDurationI, ok := stringToInt(duration)
	if ok {
		time.Sleep(time.Duration(sleepDurationI) * time.Millisecond)
	}
}

func setResponseBytes(responseBytes string, rw net.ResponseWriter) {
	respByte, ok := stringToInt(responseBytes)
	if ok {
		// 手动设置type
		rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
		bytes := make([]byte, respByte)
		// 初始化bytes，否则是0，不是常规字符，浏览器会当成二进制文件下载
		for i := 0; i < len(bytes); i++ {
			bytes[i] = '0'
		}
		_, _ = rw.Write(bytes)
	}
}

func requestMiddlewares(fields url.Values) {
	for key := range api.MiddlewareClients {
		requestMiddleware(key, fields.Get(key))
	}
}

func requestMiddleware(key string, flag string) {
	dial, ok := stringToInt(flag)
	if !ok || dial == 0 {
		return
	}
	middleware.VisitMiddleWare(key)
}

func stringToInt(s string) (int, bool) {
	if s == "" {
		return 0, false
	}
	i, err := strconv.Atoi(s)
	if err != nil {
		log.Println(err)
		return 0, false
	}
	return i, true
}

// 转发HTTP请求
func httpCallDemo2(client api.ProtocolClient, invoke string, bsleep string, breqbyte string, brespbyte string) {
	needDial, ok := stringToInt(invoke)
	if !ok || needDial == 0 {
		return
	}
	bsleepI, _ := stringToInt(bsleep)
	breqbyteI, _ := stringToInt(breqbyte)
	brespbyteI, _ := stringToInt(brespbyte)

	param := api.RequestParam{
		Sleep:           int32(bsleepI),
		RequestByteNum:  int32(breqbyteI),
		ResponseByteNum: int32(brespbyteI),
		StatusCode:      int32(200),
	}
	client.Request(param)
}

func startOrStopQuartz(quartzStr string) {
	startQuartz, ok := stringToInt(quartzStr)
	if !ok {
		return
	}

	// 锁保证多线程下不会既开启又关闭或开启多次
	mutex.Lock()
	defer mutex.Unlock()

	if startQuartz == 1 {
		quartz.StartJob()
	} else {
		quartz.StopJob()
	}
}
